<html>
    <head>
        <meta charset="utf-8">
        <title>Django 进阶学习 - 文本框过滤</title>
        <link rel="stylesheet" href="../assets/stylesheets/global.css">
        <link rel="stylesheet" href="../assets/stylesheets/words.css">
        <link rel="stylesheet" href="../assets/stylesheets/monokai.css">
        <link rel="stylesheet" href="../assets/stylesheets/table.css">
        <link rel="shortcut icon" href="../assets/images/favicon.ico" type="image/x-icon">
        <link rel="icon" href="../assets/images/favicon.ico" type="image/x-icon">
        <script>
            // 统计代码
            (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
                (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
                m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
                })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

            ga('create', 'UA-93231524-1', 'auto');
            ga('send', 'pageview');
        </script>
    </head>
    <body>
        <div id="header">
            <a href="../index.html"><div id="logo">JG</div></a>
        </div>
        <div id="container" class="typo">
            <div id="article">
                <h1>Django 进阶学习 - 文本框过滤</h1>
                <h4>Posted May 03, 2016</h4>

                <p>默认情况下django可以对列进行过滤， 但大多数是对<code>Relationship</code>列通过<code>list_filter</code> 直接指定<code>field name</code>就可以方便的进行过滤了， 但是如果实现文本框输入过滤属性， 然后通过按钮触发事件后来过滤只能通过自定义Django filter来实现</p>

<p><strong>首先自定义一个filter类</strong></p>

<p><code>filters.py</code> 默认情况下如果没有<code>filters.py</code>需要在app目录新建此模块, 推荐命名<code>filters.py</code>, 下面这个类是通用的， 所以我们要基于模型的某个字段来定义一个Filter类，继承<code>SingleTextInputFilter</code>(还是在<code>filters.py</code>)</p>
<div class="code-wrapper"><span class="lang-label">Python</span><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.contrib.admin</span> <span class="kn">import</span> <span class="n">ListFilter</span>
<span class="kn">from</span> <span class="nn">django.utils.translation</span> <span class="kn">import</span> <span class="n">ugettext_lazy</span> <span class="k">as</span> <span class="n">_</span>

<span class="k">class</span> <span class="nc">SingleTextInputFilter</span><span class="p">(</span><span class="n">ListFilter</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    renders filter form with text input and submit button</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="n">parameter_name</span> <span class="o">=</span> <span class="bp">None</span>
    <span class="n">template</span> <span class="o">=</span> <span class="s2">&quot;admin/textinput_filter.html&quot;</span>

    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">request</span><span class="p">,</span> <span class="n">params</span><span class="p">,</span> <span class="n">model</span><span class="p">,</span> <span class="n">model_admin</span><span class="p">):</span>
        <span class="nb">super</span><span class="p">(</span><span class="n">SingleTextInputFilter</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span>
            <span class="n">request</span><span class="p">,</span> <span class="n">params</span><span class="p">,</span> <span class="n">model</span><span class="p">,</span> <span class="n">model_admin</span><span class="p">)</span>
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">parameter_name</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span>
            <span class="k">raise</span> <span class="n">ImproperlyConfigured</span><span class="p">(</span>
                <span class="s2">&quot;The list filter &#39;</span><span class="si">%s</span><span class="s2">&#39; does not specify &quot;</span>
                <span class="s2">&quot;a &#39;parameter_name&#39;.&quot;</span> <span class="o">%</span> <span class="bp">self</span><span class="o">.</span><span class="vm">__class__</span><span class="o">.</span><span class="vm">__name__</span><span class="p">)</span>

        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">parameter_name</span> <span class="ow">in</span> <span class="n">params</span><span class="p">:</span>
            <span class="n">value</span> <span class="o">=</span> <span class="n">params</span><span class="o">.</span><span class="n">pop</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">parameter_name</span><span class="p">)</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">used_parameters</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">parameter_name</span><span class="p">]</span> <span class="o">=</span> <span class="n">value</span>

    <span class="k">def</span> <span class="nf">value</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Returns the value (in string format) provided in the request&#39;s</span>
<span class="sd">        query string for this filter, if any. If the value wasn&#39;t provided then</span>
<span class="sd">        returns None.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">used_parameters</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">parameter_name</span><span class="p">,</span> <span class="bp">None</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">has_output</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">return</span> <span class="bp">True</span>

    <span class="k">def</span> <span class="nf">expected_parameters</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Returns the list of parameter names that are expected from the</span>
<span class="sd">        request&#39;s query string and that will be used by this filter.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">parameter_name</span><span class="p">]</span>


    <span class="k">def</span> <span class="nf">choices</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">cl</span><span class="p">):</span>
        <span class="n">all_choice</span> <span class="o">=</span> <span class="p">{</span>
            <span class="s1">&#39;selected&#39;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">value</span><span class="p">()</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">,</span>
            <span class="s1">&#39;query_string&#39;</span><span class="p">:</span> <span class="n">cl</span><span class="o">.</span><span class="n">get_query_string</span><span class="p">({},</span> <span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">parameter_name</span><span class="p">]),</span>
            <span class="s1">&#39;display&#39;</span><span class="p">:</span> <span class="n">_</span><span class="p">(</span><span class="s1">&#39;All&#39;</span><span class="p">),</span>
        <span class="p">}</span>
        <span class="k">return</span> <span class="p">({</span>
            <span class="s1">&#39;get_query&#39;</span><span class="p">:</span> <span class="n">cl</span><span class="o">.</span><span class="n">params</span><span class="p">,</span>
            <span class="s1">&#39;current_value&#39;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">value</span><span class="p">(),</span>
            <span class="s1">&#39;all_choice&#39;</span><span class="p">:</span> <span class="n">all_choice</span><span class="p">,</span>
            <span class="s1">&#39;parameter_name&#39;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">parameter_name</span>
        <span class="p">},</span> <span class="p">)</span>

<span class="k">class</span> <span class="nc">IpFilter</span><span class="p">(</span><span class="n">SingleTextInputFilter</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;基于IP过滤, 继承SigleTextInputFilter&quot;&quot;&quot;</span>
    <span class="n">title</span> <span class="o">=</span> <span class="s2">&quot;IP&quot;</span>
    <span class="n">parameter_name</span> <span class="o">=</span> <span class="s1">&#39;ip&#39;</span>  <span class="c1">#作用model的字段名</span>
    <span class="k">def</span> <span class="nf">queryset</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">request</span><span class="p">,</span> <span class="n">queryset</span><span class="p">):</span>
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">value</span><span class="p">():</span>
            <span class="k">return</span> <span class="n">queryset</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">ip__iexact</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">value</span><span class="p">())</span> <span class="err">＃</span> <span class="err">这里自定义过滤条件</span><span class="o">.</span> <span class="bp">self</span><span class="o">.</span><span class="n">value</span><span class="p">()</span> <span class="err">是文本框输入的值</span><span class="o">.</span>
</pre></div>
</div>
<p><strong>自定义filter template</strong></p>

<p><code>admin/textinput_filter.html</code>, 直接放到本项目的template目录即可， 千万不要放到<code>django</code>包目录下的admin template目录， 如果你了解django 模版检索的过程优先级， 你应该知道我说的意思. 这里我放到<code>$MYAPP/templates/admin/textinput_filter.html</code>位置</p>
<div class="code-wrapper"><span class="lang-label">HTML</span><div class="highlight"><pre><span></span><span class="p">&lt;</span><span class="nt">h3</span><span class="p">&gt;</span>{% blocktrans with filter_title=title %} By {{ filter_title }} {% endblocktrans %}<span class="p">&lt;/</span><span class="nt">h3</span><span class="p">&gt;</span>

{#i for item, to be short in names#}
{% with choices.0 as i %}
<span class="p">&lt;</span><span class="nt">ul</span><span class="p">&gt;</span>
    <span class="p">&lt;</span><span class="nt">li</span><span class="p">&gt;</span>
        <span class="p">&lt;</span><span class="nt">form</span> <span class="na">method</span><span class="o">=</span><span class="s">&quot;get&quot;</span><span class="p">&gt;</span>
            <span class="p">&lt;</span><span class="nt">input</span> <span class="na">type</span><span class="o">=</span><span class="s">&quot;search&quot;</span> <span class="na">name</span><span class="o">=</span><span class="s">&quot;{{ i.parameter_name }}&quot;</span> <span class="na">value</span><span class="o">=</span><span class="s">&quot;{{ i.current_value|default_if_none:&quot;</span><span class="err">&quot;</span> <span class="err">}}&quot;</span><span class="p">/&gt;</span>

            {#create hidden inputs to preserve values from other filters and search field#}
            {% for k, v in i.get_query.items %}
                {% if not k == i.parameter_name %}
                    <span class="p">&lt;</span><span class="nt">input</span> <span class="na">type</span><span class="o">=</span><span class="s">&quot;hidden&quot;</span> <span class="na">name</span><span class="o">=</span><span class="s">&quot;{{ k }}&quot;</span> <span class="na">value</span><span class="o">=</span><span class="s">&quot;{{ v }}&quot;</span><span class="p">&gt;</span>
                {% endif %}
            {% endfor %}
            <span class="p">&lt;</span><span class="nt">input</span> <span class="na">type</span><span class="o">=</span><span class="s">&quot;submit&quot;</span> <span class="na">value</span><span class="o">=</span><span class="s">&quot;{% trans &#39;apply&#39; %}&quot;</span><span class="p">&gt;</span>
        <span class="p">&lt;/</span><span class="nt">form</span><span class="p">&gt;</span>
    <span class="p">&lt;/</span><span class="nt">li</span><span class="p">&gt;</span>

    {#show &quot;All&quot; link to reset current filter#}
    <span class="p">&lt;</span><span class="nt">li</span><span class="err">{%</span> <span class="na">if</span> <span class="na">i</span><span class="err">.</span><span class="na">all_choice</span><span class="err">.</span><span class="na">selected</span> <span class="err">%}</span> <span class="na">class</span><span class="o">=</span><span class="s">&quot;selected&quot;</span><span class="err">{%</span> <span class="na">endif</span> <span class="err">%}</span><span class="p">&gt;</span>
        <span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&quot;{{ i.all_choice.query_string|iriencode }}&quot;</span><span class="p">&gt;</span>
            {{ i.all_choice.display }}
        <span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>
    <span class="p">&lt;/</span><span class="nt">li</span><span class="p">&gt;</span>
<span class="p">&lt;/</span><span class="nt">ul</span><span class="p">&gt;</span>
{% endwith %}
</pre></div>
</div>
<p><strong>最后配置admin.py</strong></p>

<p><code>admin.py</code></p>
<div class="code-wrapper"><span class="lang-label">Python</span><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">controller.filters</span> <span class="kn">import</span> <span class="n">IpFilter</span>

<span class="k">class</span> <span class="nc">TriggerAdmin</span><span class="p">(</span><span class="n">admin</span><span class="o">.</span><span class="n">ModelAdmin</span><span class="p">):</span>
    <span class="n">empty_value_display</span> <span class="o">=</span> <span class="sa">u</span><span class="s1">&#39;无规则&#39;</span>
    <span class="n">list_display</span> <span class="o">=</span> <span class="p">(</span><span class="s1">&#39;__str__&#39;</span><span class="p">,</span> <span class="s1">&#39;id&#39;</span><span class="p">,</span> <span class="s1">&#39;ip&#39;</span><span class="p">,</span> <span class="s1">&#39;t_type&#39;</span><span class="p">,</span>
            <span class="s1">&#39;get_converge&#39;</span><span class="p">,</span> <span class="s1">&#39;get_switch&#39;</span><span class="p">,</span> <span class="s1">&#39;level&#39;</span><span class="p">)</span>
    <span class="n">search_fields</span> <span class="o">=</span> <span class="p">(</span><span class="s1">&#39;description&#39;</span><span class="p">,)</span>
    <span class="n">list_filter</span> <span class="o">=</span> <span class="p">(</span><span class="n">IpFilter</span><span class="p">,</span> <span class="s1">&#39;t_type&#39;</span><span class="p">,</span> <span class="s1">&#39;converge_role&#39;</span><span class="p">,</span> <span class="s1">&#39;switch_role&#39;</span><span class="p">,</span> <span class="s1">&#39;level&#39;</span><span class="p">)</span> <span class="c1"># 直接把IpFilter类写进去</span>
</pre></div>
</div>
<p><strong>配置完成</strong></p>

            </div>
            <div id="footer">
                <a href="../words.html"><div id="more-words">MORE WORDS</div></a>
            </div>
        </div>
    </body>
</html>